package com.vichat.common.util;

import java.util.*;

/**
 * Table Bean 基础类
 * Created by dongqilin on 4/18/16.
 */
public class TableBean {

    public static class Builder {

        public static final String COUNT_NAME = "total";

        private List<Object> params;

        private String table;
        private String orderBy = "";
        private String limit = "";
        private String groupBy = "";
        private String having = "";

        private StringBuilder main = new StringBuilder();
        private StringBuilder where = new StringBuilder();
        private Map<String, String> wMap = new HashMap<>();

        // for insert
        private boolean insert = false;
        private Map<String, String> iMap;

        // for update
        private boolean update = false;
        private Map<String, String> uMap;
        private List<Boolean> uOps;

        public Builder(String table) {
            this(table, null);
        }

        public Builder(String table, List<Object> params) {
            this.table = table;
            this.params = params;
        }

        public Builder insert() {
            insert = true;
            iMap = new HashMap<>();
            main.append("insert into ").append(table);
            return this;
        }

        public Builder add(String key, Object value) {
            if (!insert) throw new RuntimeException("应该先调用insert方法");
            iMap.put(key, parseValue(value));
            return this;
        }

        public Builder add(Map<String, String> data) {
            if (!insert) throw new RuntimeException("应该先调用insert方法");
            this.iMap.putAll(data);
            return this;
        }

        public Builder update() {
            update = true;
            uMap = new HashMap<>();
            uOps = new ArrayList<>();
            main.append("update ").append(table).append(" set ");
            return this;
        }

        public Builder set(String key, Object value) {
            return set(key, parseValue(value), null);
        }

        public Builder setAdd(String key, long value) {
            return set(key, String.valueOf(value), true);
        }

        public Builder setMinus(String key, long value) {
            return set(key, String.valueOf(value), false);
        }

        private Builder set(String key, String value, Boolean ops) {
            if (!update) throw new RuntimeException("应该先调用update方法");
            check(key, value);
            uMap.put(key, value);
            uOps.add(ops);
            return this;
        }

        public Builder delete() {
            main.append("delete from ").append(table);
            return this;
        }


        public Builder select() {
            main.append("select * from ").append(table);
            return this;
        }

        public Builder select(String... columns) {
            String select = Arrays.toString(columns);
            select = select.substring(1, select.length());
            main.append("select ").append(select).append(" from ").append(table);
            return this;
        }

        public Builder count() {
            main.append("select count(*) total from ").append(table);
            return this;
        }


        /**
         * ------查询条件开始------
         */
        public Builder equal(String key, Object value) {
            return where(key, "=", value);
        }

        public Builder notEqual(String key, Object value) {
            return where(key, "<>", value);
        }

        public Builder lessThan(String key, Object value) {
            return where(key, "<", value);
        }

        public Builder lessThanEqual(String key, Object value) {
            return where(key, "<=", value);
        }

        public Builder greaterThan(String key, Object value) {
            return where(key, ">", value);
        }

        public Builder greaterThanEqual(String key, Object value) {
            return where(key, ">=", value);
        }

        public Builder where(String key, String ops, Object value) {
            check(key, value);
            wMap.put(key + " " + ops + " ", parseValue(value));
            return this;
        }

        public Builder like(String key, Object value) {
            check(key, value);
            where.append(" and ").append(key).append(" like '%").append(parseValue(value)).append("%'");
            return this;
        }

        public Builder like(String[] keys, Object value) {
            check(keys, value);
            where.append(" and (");
            for (int i = 0; i < keys.length; i++) {
                if (i > 0) {
                    where.append(" or ");
                }
                where.append(keys[i]).append(" like '%").append(parseValue(value)).append("%'");
            }
            where.append(")");
            return this;
        }

        public Builder in(String key, List value) {
            if (value != null && value.size() > 0) {
                in(key, value.toArray());
            }
            return this;
        }

        public Builder in(String key, Object[] value) {
            check(key);
            if (value != null && value.length > 0) {
                where.append(" and ").append(key).append(" in(");
                if (params != null) {
                    for (int v = 0; v < value.length; v++) {
                        if (v == 0)
                            where.append("?");
                        else
                            where.append(",?");
                        params.add(parseValue(value[v]));
                    }
                } else {
                    String in = Arrays.deepToString(value);
                    in = "'" + in.substring(1, in.length() - 1).replaceAll(", ", "', '") + "'";
                    where.append(in);
                }
                where.append(")");
            }
            return this;
        }

        public Builder between(String key, Object start, Object end) {
            check(key, new Object[]{start, end});
            if (params != null) {
                where.append(" and ").append(key).append(" between ? and ?");
                params.add(parseValue(start));
                params.add(parseValue(end));
            } else {
                where.append(" and ").append(key).append(" between '").append(parseValue(start)).append("' and '").append(parseValue(end)).append("'");
            }
            return this;
        }

        public Builder isNull(String key) {
            where.append(" and ").append(key).append(" is null");
            return this;
        }

        public Builder isNotNull(String key) {
            where.append(" and (").append(key).append(" is not null").append(" and ").append(key).append(" != '')");
            return this;
        }

        public Builder or(String key, Object... values) {
            check(key);
            where.append(" and (");
            for (int i = 0; i < values.length; i++) {
                if (i > 0) {
                    where.append(" or ");
                }
                if (values[i] == null) {
                    where.append(key).append(" is null");
                } else {
                    if (params != null) {
                        where.append(key).append(" = ?");
                        params.add(parseValue(values[i]));
                    } else {
                        where.append(key).append(" = '").append(parseValue(values[i])).append("'");
                    }
                }
            }
            where.append(")");
            return this;
        }

        public Builder orNull(String key, Object value) {
            Object[] values = new Object[]{null, value};
            or(key, values);
            return this;
        }

        public Builder orKey(String[] keys, Object value) {
            if (keys == null || keys.length == 0) {
                throw new RuntimeException("KEYS不能为空");
            }
            where.append(" and (");
            for (int i = 0; i < keys.length; i++) {
                if (i > 0) {
                    where.append(" or ");
                }
                if (value == null || value.toString().length() == 0) {
                    where.append(keys[i]).append(" is null");
                } else {
                    if (params != null) {
                        where.append(keys[i]).append(" = ?");
                        params.add(parseValue(value));
                    } else {
                        where.append(keys[i]).append(" = '").append(parseValue(value)).append("'");
                    }
                }
            }
            where.append(")");
            return this;
        }

        /**
         * 自定义条件
         */
        public Builder condition(String condition) {
            if (condition != null && condition.length() > 3)
                where.append(" and ").append(condition);
            return this;
        }

        /**
         * ------查询条件结束------
         */

        public Builder groupBy(String key) {
            check(key);
            groupBy = " group by " + key;
            return this;
        }

        public Builder having(String key) {
            check(key);
            having = " having " + key;
            return this;
        }

        public Builder orderBy(String key, boolean asc) {
            check(key);
            orderBy = " order by " + key + (asc ? " asc" : " desc");
            return this;
        }

        public Builder orderBy(String[] keys, boolean asc) {
            boolean[] order = new boolean[keys.length];
            for(int i = 0; i < keys.length; i++)
                order[i] = asc;
            orderBy(keys, order);
            return this;
        }

        public Builder orderBy(String[] keys, boolean[] asc) {
            check(keys, asc);
            String key = "";
            for (int i = 0; i < keys.length; i++) {
                key += ", " + keys[i] + (asc[i] ? " asc" : " desc");
            }
            orderBy = " order by" + key.substring(1);
            return this;
        }

        public Builder limit(long size) {
            limit = " limit " + size;
            return this;
        }

        public Builder limit(long start, long size) {
            limit = " limit " + start + (size > 0 ? "," + size : "");
            return this;
        }

        public Builder limit2(int page, long size) {
            if (page == 0) throw new IllegalArgumentException("page不能小于1");
            long start = (page - 1) * size;
            limit = " limit " + start + "," + size;
//            if(params == null){
//            } else {
//                limit = " limit ?, ?";
//                params.add(start);
//                params.add(size);
//            }
            return this;
        }

        public String build() {

            if (insert) {
                StringBuilder column = new StringBuilder(), value = new StringBuilder();
                for (String key : iMap.keySet()) {
                    column.append(", `").append(key).append("`");
                    String v = iMap.get(key);
                    if (params == null) {
                        if (v == null || v.length() == 0) {
                            value.append(", null");
                        } else {
                            value.append(", '").append(v).append("'");
                        }
                    } else {
                        value.append(", ?");
                        params.add(v);
                    }
                }
                main.append(" (").append(column.toString().substring(1)).append(")");
                main.append(" values (").append(value.toString().substring(1)).append(")");
                return main.toString();
            }

            String sql = main.toString();
            if (update) {
                if (uMap == null || uMap.size() == 0) {
                    throw new RuntimeException("更新列不能为空");
                }
                int i = 0;
                for (String key : uMap.keySet()) {
                    String value = uMap.get(key);
                    Boolean ops = uOps.get(i);
                    if (params != null) {
                        if (ops != null) {
                            sql += key + " = " + key + (ops ? " + " : " - ") + "?";
                        } else {
                            sql += key + " = " + "?";
                        }
                        params.add(value);
                    } else {
                        if (ops != null) {
                            sql += key + " = " + key + (ops ? " + " : " - ") + value;
                        } else {
                            sql += key + " = '" + value + "'";
                        }
                    }
                    if(i != uMap.size() - 1) sql += ", ";
                    i++;
                }
            }
            StringBuilder wh = new StringBuilder();
            if (wMap.size() > 0) {
                if (params != null) {
                    for (String key : wMap.keySet()) {
                        wh.append(" and ").append(key).append("?");
                        params.add(wMap.get(key));
                    }
                } else {
                    for (String key : wMap.keySet()) {
                        wh.append(" and ").append(key).append("'").append(wMap.get(key)).append("'");
                    }
                }
            }
            String condition = wh.append(where).toString();
            if(condition.length() > 5){
                condition = condition.substring(5);
                condition = " where " + condition;
            }
            return sql + condition + groupBy + having + orderBy + limit;
        }

        private String parseValue(Object value) {
            if (value == null)
                return "";
            else if (value instanceof Date)
                return DateUtil.getFormattedDateTime((Date) value);
            return String.valueOf(value);
        }

        private void check(String key) {
            if (key == null || key.length() < 1) {
                throw new RuntimeException("查询条件不能为空");
            }
        }

        private void check(String[] key, Object value) {
            if (key == null || key.length < 1) {
                throw new RuntimeException("查询条件不能为空");
            }
            if (value == null) {
                throw new RuntimeException(("查询条件值不能这空1"));
            }
        }

        private void check(String key, Object value) {
            check(key, new Object[]{value});
        }

        private void check(String key, Object[] values) {
            check(key);

            if (values == null || values.length < 1) {
                throw new RuntimeException(("查询条件值不能这空1"));
            }
            for (Object value : values) {
                if (value == null || parseValue(value).length() < 1) {
                    throw new RuntimeException(("查询条件值不能这空2"));
                }
            }

        }

    }


}
